﻿using System;
using System.Net;
using System.IO;
using System.Diagnostics;

namespace NeroConnect.Network
{
	class HttpRequest : IRequest
	{
		HttpWebRequest _webRequest;

		public HttpRequest(Uri requestUri)
		{
			_webRequest = WebRequest.Create(requestUri) as HttpWebRequest;
            _webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
			if (_webRequest == null)
				throw new NotSupportedException("only HTTP or HTTPS is supported");
		}

		public bool HaveResponse
		{
			get
			{
				return _webRequest.HaveResponse;
			}
		}

		public WebHeaderCollection Headers
		{
			get
			{
				return _webRequest.Headers;
			}
			set
			{
				_webRequest.Headers = value;
			}
		}

		public string Method
		{
			get
			{
				return _webRequest.Method;
			}
			set
			{
				_webRequest.Method = value;
			}
		}

		public Uri RequestUri
		{
			get { return _webRequest.RequestUri; }
		}

		public bool SendChunked
		{
			get
			{
				return _webRequest.SendChunked;
			}
			set
			{
				_webRequest.SendChunked = value;
			}
		}

		public int Timeout
		{
			get
			{
				return _webRequest.Timeout;
			}
			set
			{
				_webRequest.Timeout = value;
			}
		}

		System.DateTime _getRequestStreamStart = DateTime.Now;
		public IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state)
		{
			_getRequestStreamStart = DateTime.Now;
            //Trace.TraceInformation("BEGINGETREQUESTSTREAM - CONNECTIONINFO(limit={0}, count={1}, pipelining={2}, address={3}, leasetimeout={4})",
            //    _webRequest.ServicePoint.ConnectionLimit, _webRequest.ServicePoint.CurrentConnections, _webRequest.ServicePoint.SupportsPipelining, _webRequest.ServicePoint.Address, _webRequest.ServicePoint.ConnectionLeaseTimeout);
			try
			{
				if (_webRequest.ContentLength > 0)
					_webRequest.AllowWriteStreamBuffering = false;
				return _webRequest.BeginGetRequestStream(callback, state);
			}
			catch (System.Net.WebException ex)
			{
				throw new WebExceptionImpl(ex);
			}
		}

		System.DateTime _getResponseStart = DateTime.Now;
		public IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
		{
			_getResponseStart = DateTime.Now;
            //Trace.TraceInformation("BEGINGETRESPONSE - CONNECTIONINFO(limit={0}, count={1}, pipelining={2}, address={3}, leasetimeout={4})",
            //    _webRequest.ServicePoint.ConnectionLimit, _webRequest.ServicePoint.CurrentConnections, _webRequest.ServicePoint.SupportsPipelining, _webRequest.ServicePoint.Address, _webRequest.ServicePoint.ConnectionLeaseTimeout);
			try
			{
				return _webRequest.BeginGetResponse(callback, state);
			}
			catch (System.Net.WebException ex)
			{
				throw new WebExceptionImpl(ex);
			}
		}

		public Stream EndGetRequestStream(IAsyncResult asyncResult)
		{
			TimeSpan duration = DateTime.Now - _getRequestStreamStart;
            //Trace.TraceInformation("TIME: " + duration + " - ENDGETREQUESTSTREAM - CONNECTIONINFO(limit={0}, count={1}, pipelining={2}, address={3}, leasetimeout={4})",
            //    _webRequest.ServicePoint.ConnectionLimit, _webRequest.ServicePoint.CurrentConnections, _webRequest.ServicePoint.SupportsPipelining, _webRequest.ServicePoint.Address, _webRequest.ServicePoint.ConnectionLeaseTimeout);
			try
			{
				return new ConnectStream(new LogStream(_webRequest.EndGetRequestStream(asyncResult)));
			}
			catch (System.Net.WebException ex)
			{
				throw new WebExceptionImpl(ex);
			}
		}

		public IResponse EndGetResponse(IAsyncResult asyncResult)
		{
			TimeSpan duration = DateTime.Now -_getResponseStart;
            //Trace.TraceInformation("TIME: " + duration + " - ENDGETRESPONSE - CONNECTIONINFO(limit={0}, count={1}, pipelining={2}, address={3}, leasetimeout={4})",
            //    _webRequest.ServicePoint.ConnectionLimit, _webRequest.ServicePoint.CurrentConnections, _webRequest.ServicePoint.SupportsPipelining, _webRequest.ServicePoint.Address, _webRequest.ServicePoint.ConnectionLeaseTimeout);
			try
			{
				return new HttpResponse(_webRequest.EndGetResponse(asyncResult) as HttpWebResponse);
			}
			catch (System.Net.WebException ex)
			{
				throw new WebExceptionImpl(ex);
			}
		}

		public Stream GetRequestStream()
		{
            //Trace.TraceInformation("GETREQUESTSTREAM - CONNECTIONINFO(limit={0}, count={1}, pipelining={2}, address={3}, leasetimeout={4})",
            //    _webRequest.ServicePoint.ConnectionLimit, _webRequest.ServicePoint.CurrentConnections, _webRequest.ServicePoint.SupportsPipelining, _webRequest.ServicePoint.Address, _webRequest.ServicePoint.ConnectionLeaseTimeout);
			try
			{
				return new ConnectStream(new LogStream(_webRequest.GetRequestStream()));
			}
			catch (System.Net.WebException ex)
			{
				throw new WebExceptionImpl(ex);
			}
		}

		public IResponse GetResponse()
		{
            //Trace.TraceInformation("GETRESPONSE - CONNECTIONINFO(limit={0}, count={1}, pipelining={2}, address={3}, leasetimeout={4})",
            //    _webRequest.ServicePoint.ConnectionLimit, _webRequest.ServicePoint.CurrentConnections, _webRequest.ServicePoint.SupportsPipelining, _webRequest.ServicePoint.Address, _webRequest.ServicePoint.ConnectionLeaseTimeout);
			try
			{
				return new HttpResponse(_webRequest.GetResponse() as HttpWebResponse);
			}
			catch (System.Net.WebException ex)
			{
				throw new WebExceptionImpl(ex);
			}
		}

		public ServicePoint ServicePoint
		{
			get { return _webRequest.ServicePoint; }
		}

		public long ContentLength
		{
			get
			{
				return _webRequest.ContentLength;
			}
			set
			{
				_webRequest.ContentLength = value;
			}
		}

		public string ContentType
		{
			get
			{
				return _webRequest.ContentType;
			}
			set
			{
				_webRequest.ContentType = value;
			}
		}

		public bool KeepAlive
		{
			get
			{
				return _webRequest.KeepAlive;
			}
			set
			{
				_webRequest.KeepAlive = value;
			}
		}

		public string TransferEncoding
		{
			get
			{
				return _webRequest.TransferEncoding;
			}
			set
			{
				_webRequest.TransferEncoding = value;
			}
		}

		public string UserAgent
		{
			get
			{
				return _webRequest.UserAgent;
			}
			set
			{
				_webRequest.UserAgent = value;
			}
		}

		public DateTime IfModifiedSince
		{
			get
			{
				return _webRequest.IfModifiedSince;
			}
			set
			{
				_webRequest.IfModifiedSince = value;
			}
		}

		public void Abort()
		{
			_webRequest.Abort();
		}

		public CookieContainer CookieContainer
		{
			get
			{
				return _webRequest.CookieContainer;
			}
			set
			{
				_webRequest.CookieContainer = value;
			}
		}

		public void AddRange(int range)
		{
			_webRequest.AddRange(range);
		}

		public void AddRange(int from, int to)
		{
			_webRequest.AddRange(from, to);
		}

		public IWebProxy Proxy
		{
			get
			{
				return _webRequest.Proxy;
			}
			set
			{
				_webRequest.Proxy = value;
			}
		}

		public System.Net.Cache.RequestCachePolicy CachePolicy
		{
			get
			{
				return _webRequest.CachePolicy;
			}
			set
			{
				_webRequest.CachePolicy = value;
			}
		}
	}
}
